package com.qfmy.app.lucene;

import com.qfmy.app.vo.novel.BookVo;
import com.qfmy.model.entity.novel.Book;
import com.qfmy.model.enums.novel.BookStatus;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;


import java.util.ArrayList;
import java.util.List;

/**
 * LuceneUtils类用于创建和搜索书籍索引。
 */
@SuppressWarnings("all")
public class LuceneUtils {
    // 使用RAMDirectory创建内存中的索引存储
    private static Directory index = new RAMDirectory();
    // 使用StandardAnalyzer作为文本分析器
    private static StandardAnalyzer analyzer = new StandardAnalyzer();

    /**
     * 创建书籍索引
     *
     * @param books 书籍列表，用于遍历并创建索引
     * @throws Exception 如果索引创建过程中发生错误，则抛出异常
     */
    public static void createIndex(List<Book> books) throws Exception {
        // 创建IndexWriterConfig对象，用于配置索引写入的分析器
        IndexWriterConfig config = new IndexWriterConfig(analyzer);

        // 创建IndexWriter对象，用于写入索引
        IndexWriter writer = new IndexWriter(index, config);

        for (Book book : books) {
            Document doc = new Document();

            // 添加书的ID字段，使用StringField类型，存储但不分析文本
            doc.add(new StringField("book_id", String.valueOf(book.getBookId()), Field.Store.YES));

            // 添加书名字段，使用TextField类型，存储并分析文本
            doc.add(new TextField("book_name", book.getBookName(), Field.Store.YES));

            // 添加作者字段，使用TextField类型，存储并分析文本
            doc.add(new TextField("author", book.getAuthor(), Field.Store.YES));

            // 添加类型字段，使用StringField类型，存储但不分析文本
            doc.add(new StringField("type", book.getType(), Field.Store.YES));

            // 添加描述字段，使用TextField类型，存储并分析文本
            doc.add(new TextField("des", book.getDes(), Field.Store.YES));

            // 添加封面URL字段，使用StringField类型，存储但不分析文本
            doc.add(new StringField("img_url", book.getImgUrl(), Field.Store.YES));

            // 添加状态字段，使用StringField类型，存储但不分析文本
            doc.add(new StringField("status", String.valueOf(book.getStatus()), Field.Store.YES));

            // 添加总评分字段，使用DoublePoint类型，用于数值范围查询
            doc.add(new DoublePoint("total_score", book.getTotalScore()));
            // 同时使用StringField存储总评分，以便在搜索结果中显示
            doc.add(new StringField("total_score_str", String.valueOf(book.getTotalScore()), Field.Store.YES));

            // 添加阅读人数字段，使用IntPoint类型，用于数值范围查询
            doc.add(new IntPoint("read_book", book.getReadBook()));
            // 同时使用StringField存储阅读人数，以便在搜索结果中显示
            doc.add(new StringField("read_book_str", String.valueOf(book.getReadBook()), Field.Store.YES));

            // 添加评分人数字段，使用IntPoint类型，用于数值范围查询
            doc.add(new IntPoint("rating_count", book.getRatingCount()));
            // 同时使用StringField存储评分人数，以便在搜索结果中显示
            doc.add(new StringField("rating_count_str", String.valueOf(book.getRatingCount()), Field.Store.YES));

            // 将Document对象添加到索引中
            writer.addDocument(doc);
        }

        // 关闭IndexWriter对象，释放资源
        writer.close();
    }

    /**
     * 搜索功能
     *
     * 此方法使用Lucene库根据关键词搜索书籍信息。它通过查询书籍名称、作者和类型字段来获取最相关的书籍。
     *
     * @param keyword 搜索框中输入的关键词
     * @return 包含搜索结果的BookVo对象列表
     * @throws Exception 如果搜索过程中发生错误，则抛出异常
     */
    public static List<BookVo> searchBooks(String keyword) throws Exception {
        // 存储搜索结果的列表
        List<BookVo> results = new ArrayList<>();

        // 打开索引目录以供读取
        IndexReader reader = DirectoryReader.open(index);

        // 创建IndexSearcher对象以执行搜索
        IndexSearcher searcher = new IndexSearcher(reader);

        // 定义要搜索的字段：书籍名称、作者和类型
        String[] fields = {"book_name", "author", "type"};

        // 创建MultiFieldQueryParser以解析查询
        MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer);

        // 解析用户输入的关键词以生成查询对象
        Query query = parser.parse(keyword);

        // 执行搜索，返回最相关的15个文档
        TopDocs topDocs = searcher.search(query, 15);

        // 遍历搜索结果，将每个文档转换为BookVo对象并添加到结果列表中
        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            Document doc = searcher.doc(scoreDoc.doc);
            BookVo bookVo = new BookVo();
            bookVo.setBookId(Integer.parseInt(doc.get("book_id")));
            bookVo.setBookName(doc.get("book_name"));
            bookVo.setAuthor(doc.get("author"));
            bookVo.setType(doc.get("type"));
            bookVo.setDes(doc.get("des"));
            bookVo.setImgUrl(doc.get("img_url"));
            bookVo.setStatus(BookStatus.getDescByCode(Integer.parseInt(doc.get("status"))));
            bookVo.setTotalScore(Double.parseDouble(doc.get("total_score_str")));
            bookVo.setReadBook(Integer.parseInt(doc.get("read_book_str")));
            bookVo.setRatingCount(Integer.parseInt(doc.get("rating_count_str")));
            results.add(bookVo);
        }

        // 关闭IndexReader
        reader.close();

        // 返回搜索结果
        return results;
    }
}